package com.unnet.yjs.controller.api.v1;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.unnet.yjs.annotation.HttpMethod;
import com.unnet.yjs.annotation.SysLog;
import com.unnet.yjs.base.ContainerProperties;
import com.unnet.yjs.entity.Base64Vo;
import com.unnet.yjs.service.OssFileRecordService;
import com.unnet.yjs.service.UploadService;
import com.unnet.yjs.util.Base64ConvertUtil;
import com.unnet.yjs.util.RestResponse;
import com.unnet.yjs.util.ToolUtil;
import com.xiaoleilu.hutool.date.DatePattern;
import com.xiaoleilu.hutool.date.DateUtil;
import com.xiaoleilu.hutool.io.FileUtil;
import com.xiaoleilu.hutool.map.MapUtil;
import com.xiaoleilu.hutool.util.StrUtil;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import sun.net.www.protocol.http.HttpURLConnection;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;


/**
 * Email: love1208tt@foxmail.com
 * Copyright (c)  2019. missbe
 *
 * @author lyg   19-7-2 上午11:12
 **/

@RestController
@Api(tags = "FileController", description = "文件上传控制器")
@RequestMapping("/api/v1/resource/file/")
public class FileController {
    private static final Logger LOGGER = LoggerFactory.getLogger(FileController.class);

    @Resource
    private OssFileRecordService ossFileRecordService;

    @Resource
    private ContainerProperties containerProperties;

    @Value("uploadType")
    private String uploadType;

    @Value("localUploadPath")
    private String localUploadPath;

    @Resource
    @Qualifier("localService")
    private UploadService localService;

    @Resource
    @Qualifier("myOssService")
    private UploadService myossService;

    @Resource
    @Qualifier("paasService")
    private UploadService paasService;


    @GetMapping("remove")
    @ApiOperation(value = "删除对象存储中的文件", httpMethod = HttpMethod.GET)
    public RestResponse remove(@RequestParam(value = "fileNames") List<String> fileNames) {
        Boolean isDelete;
        if ("local".equals(containerProperties.getFileUploadType())) {
            isDelete = localService.delete(fileNames);
        } else if ("myOss".equals(containerProperties.getFileUploadType())) {
            isDelete = myossService.delete(fileNames);
        } else if ("paas".equals(containerProperties.getFileUploadType())) {
            isDelete = paasService.delete(fileNames);
        } else {
            ///其它也采用本地上传-配置名称错误时
            isDelete = localService.delete(fileNames);
        }
        if (!isDelete) {
            return RestResponse.failure("删除文件失败");
        }
        return RestResponse.success();
    }

    private void deleteCacheFile(String fileName) {
        if (Objects.nonNull(fileName)) {
            File file = new File(containerProperties.getFileCacheLocation() + fileName);
            if (file.isFile()) {
                boolean suc = false;
                try {
                    suc = Files.deleteIfExists(file.toPath());
                } catch (IOException e) {
                    LOGGER.error("清除缓存文件出现问题:" + e.getLocalizedMessage());
                    ///将该文件加入定时任务队列进行删除
                    ossFileRecordService.insertDeleteRecord(fileName);
                    LOGGER.info("缓存目录：["+containerProperties.getFileCacheLocation()+"],文件["+file.getName()+"]删除失败加入定时删除队列.");
                }
                if (suc) {
                    LOGGER.info("缓存目录：["+containerProperties.getFileCacheLocation()+"],文件["+file.getName()+"]删除成功.");
                }
            }
        }
    }

    @PostMapping(value = "upload/video", consumes = "multipart/*", headers = "content-type=multipart/form-data")
    @ApiOperation(value = "视频上传接口", httpMethod = HttpMethod.POST)
    @ApiImplicitParams({@ApiImplicitParam(name = "s_areaId", value = "地州唯一ID", defaultValue = "CD0281", paramType = "query"), @ApiImplicitParam(name = "s_rename", value = "文件是否重命名[true|false]", defaultValue = "true", paramType = "query"), @ApiImplicitParam(name = "s_remarks", value = "文件备注信息，例如[网盘文件：CloudDisk,平台文件：PlatformFile]", defaultValue = "PlatformFile", paramType = "query")})
    @SysLog("上传视频接口")
    public RestResponse uploadVideo(@ApiParam(value = "上传的视频文件", required = true) MultipartFile file, HttpServletRequest httpServletRequest) {
        if (file == null) {
            return RestResponse.failure("上传文件为空 ");
        }

        ///更新缓存操作
        deleteCacheFile(file.getOriginalFilename());

        String areaId = httpServletRequest.getParameter("s_areaId");
        if (StrUtil.isBlank(areaId)) {
            areaId = "*";
        }
        String isRename = httpServletRequest.getParameter("s_rename");
        if (isRename == null) {
            isRename = "false";
        }
        String remarks = httpServletRequest.getParameter("s_remarks");
        if (remarks == null) {
            remarks = "PlatformFile";
        }
        Map<String, Object> parameterMap = MapUtil.newHashMap();
        parameterMap.put("AREA_ID", areaId);
        parameterMap.put("isRename", isRename);
        parameterMap.put("remarks", remarks);
        String url;
        String directory = "video";
        Map<String, String> m = Maps.newHashMap();
        try {
            if ("local".equals(containerProperties.getFileUploadType())) {
                url = localService.upload(file, directory, parameterMap);
                m.put("type", "local");
            } else if ("myOss".equals(containerProperties.getFileUploadType())) {
                url = myossService.upload(file, directory, parameterMap);
                m.put("type", "oss");
            } else if ("paas".equals(containerProperties.getFileUploadType())) {
                url = paasService.upload(file, directory, parameterMap);
                m.put("type", "paas");
            } else {
                ///其它也采用本地上传-配置名称错误时
                url = localService.upload(file, parameterMap);
                m.put("type", "local");
            }
            if (url.startsWith("ERROR:")) {
                return RestResponse.failure(url);
            }
            m.put("size", String.valueOf(file.getSize()));
            m.put("url", url);
            m.put("name", file.getOriginalFilename());
            LOGGER.info(httpServletRequest.getRemoteHost() + "上传图片->name:" + file.getOriginalFilename() + " url:" + url);
        } catch (Exception e) {
            LOGGER.info(httpServletRequest.getRemoteHost() + "上传图片出错->" + e.getLocalizedMessage());
            return RestResponse.failure(e.getMessage());
        }
        return RestResponse.success().setData(m);
    }

    private File resetImageSize(MultipartFile file, int width, int height) throws IOException {
        String originalFilename = file.getOriginalFilename();
        BufferedImage bimage = ImageIO.read(file.getInputStream());
        Image image = bimage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
        BufferedImage target = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        Graphics graphics = target.getGraphics();
        graphics.drawImage(image, 0, 0, null);
        graphics.dispose();
        assert originalFilename != null;
        String suffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        originalFilename = originalFilename.substring(0, originalFilename.lastIndexOf("."));
        String randdomText = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
        File rootFile = ResourceUtils.getFile("classpath:application.yml");
        String filePath = rootFile.getParentFile().getAbsolutePath() + File.separator + "static" + File.separator + "upload" + File.separator + "tmp" + File.separator + randdomText + "-" + originalFilename + "." + suffix;
        ///创建目录
        FileUtil.mkParentDirs(filePath);
        File targetFile = File.createTempFile("yjs_image_", "." + suffix);
        ImageIO.write(target, suffix, targetFile);
        return targetFile;
    }

    private boolean isImage(MultipartFile file) {
        String contentType = file.getContentType();
        return StrUtil.endWith(contentType, "jpg") || StrUtil.endWith(contentType, "jpeg") || StrUtil.endWith(contentType, "png") || StrUtil.endWith(contentType, "jpg");
    }

    @PostMapping(value = "upload/file", headers = "content-type=multipart/form-data")
    @ApiOperation(value = "图片|文件上传接口", httpMethod = HttpMethod.POST)
    @ApiImplicitParams({@ApiImplicitParam(name = "s_areaId", value = "地州唯一ID", defaultValue = "CD0281", paramType = "query"), @ApiImplicitParam(name = "s_rename", value = "文件是否重命名", defaultValue = "true", paramType = "query"), @ApiImplicitParam(name = "s_remarks", value = "文件备注信息，例如[网盘文件：CloudDisk,平台文件：PlatformFile]", defaultValue = "PlatformFile", paramType = "query"), @ApiImplicitParam(name = "width", value = "指定图片宽度[按指定大小压缩]", dataType = "Integer", paramType = "query"), @ApiImplicitParam(name = "height", value = "指定图片高度[按指定大小压缩]", dataType = "Integer", paramType = "query")})
    @SysLog("图片和文件上传接口")
    public RestResponse uploadFile(@ApiParam(value = "上传的图片文件", required = true) MultipartFile file, @RequestParam(value = "width", required = false, defaultValue = "-1") int width, @RequestParam(value = "height", required = false, defaultValue = "-1") int height, HttpServletRequest httpServletRequest) {
        if (file == null) {
            return RestResponse.failure("上传文件为空 ");
        }
        ///更新缓存操作
        deleteCacheFile(file.getOriginalFilename());

        String areaId = httpServletRequest.getParameter("s_areaId");
        if (StrUtil.isBlank(areaId)) {
            areaId = "*";
        }
        String isRename = httpServletRequest.getParameter("s_rename");
        if (isRename == null) {
            isRename = "false";
        }
        String remarks = httpServletRequest.getParameter("s_remarks");
        if (remarks == null) {
            remarks = "PlatformFile";
        }
        Map<String, Object> parameterMap = MapUtil.newHashMap();
        parameterMap.put("AREA_ID", areaId);
        parameterMap.put("isRename", isRename);
        parameterMap.put("remarks", remarks);
        ///如果是图片,未指定尺寸不进行压缩
        if (isImage(file) && (width != -1 && height != -1)) {
            File resFile;
            try {
                resFile = resetImageSize(file, width, height);
                FileInputStream fileInputStream = new FileInputStream(resFile);
                MultipartFile resMultipartFile = new MockMultipartFile(resFile.getName(), resFile.getName(), ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream);
                if (resMultipartFile.getSize() > 0) {
                    file = resMultipartFile;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        String url;
        Map<String, String> m = Maps.newHashMap();
        try {
            if ("local".equals(containerProperties.getFileUploadType())) {
                url = localService.upload(file, parameterMap);
                m.put("type", "local");
            } else if ("myOss".equals(containerProperties.getFileUploadType())) {
                m.put("type", "oss");
                url = myossService.upload(file, parameterMap);
            } else if ("paas".equals(containerProperties.getFileUploadType())) {
                url = paasService.upload(file, parameterMap);
                m.put("type", "paas");
            } else {
                ///其它也采用本地上传-配置名称错误时
                url = localService.upload(file, parameterMap);
                m.put("type", "local");
            }
            if (url.startsWith("ERROR:")) {
                return RestResponse.failure(url);
            }
            m.put("size", String.valueOf(file.getSize()));
            m.put("url", url);
            m.put("name", file.getOriginalFilename());
            LOGGER.info(httpServletRequest.getRemoteHost() + "上传文件->name:" + file.getOriginalFilename() + " url:" + url);
        } catch (Exception e) {
            LOGGER.info(httpServletRequest.getRemoteHost() + "上传文件出错->" + e.getMessage());
            return RestResponse.failure(e.getMessage());
        }
        return RestResponse.success().setData(m);
    }

    @PostMapping("upload/base64")
    @ApiOperation(value = "Bease64上传接口", httpMethod = HttpMethod.POST)
    @ApiImplicitParams({@ApiImplicitParam(name = "s_areaId", value = "地州唯一ID", defaultValue = "CD0281", paramType = "query"), @ApiImplicitParam(name = "s_rename", value = "文件是否重命名", defaultValue = "true", paramType = "query"), @ApiImplicitParam(name = "s_remarks", value = "文件备注信息，例如[网盘文件：CloudDisk,平台文件：PlatformFile]", defaultValue = "PlatformFile", paramType = "query"),})
    @SysLog("base64格式文件上传")
    public RestResponse uploadBase64(@ApiParam Base64Vo file, HttpServletRequest httpServletRequest) {
        if (Objects.isNull(file)) {
            return RestResponse.failure("base64对象不能为空");
        }
        if (StringUtils.isBlank(file.getFile())) {
            return RestResponse.failure("图片不能为空");
        }
        String areaId = file.getS_areaId();
        if (StrUtil.isBlank(areaId)) {
            areaId = "*";
        }
        String isRename = file.getS_rename();
        if (isRename == null) {
            isRename = "false";
        }
        String remarks = httpServletRequest.getParameter("s_remarks");
        if (remarks == null) {
            remarks = "PlatformFile";
        }
        MultipartFile multipartFile;
        if (StrUtil.isBlank(file.getName())) {
            multipartFile = Base64ConvertUtil.base64toMultipart(file.getFile(), DateUtil.format(new Date(), "yyyyMMddhhmmss") + System.currentTimeMillis());
        } else {
            multipartFile = Base64ConvertUtil.base64toMultipart(file.getFile(), file.getName());
        }
        Map<String, Object> parameterMap = MapUtil.newHashMap();
        parameterMap.put("AREA_ID", areaId);
        parameterMap.put("isRename", isRename);
        parameterMap.put("remarks", remarks);
        String url;
        Map<String, String> m = Maps.newHashMap();
        try {
            if ("local".equals(containerProperties.getFileUploadType())) {
                url = localService.upload(multipartFile, parameterMap);
                m.put("type", "local");
            } else if ("myOss".equals(containerProperties.getFileUploadType())) {
                m.put("type", "oss");
                url = myossService.upload(multipartFile, parameterMap);
            } else if ("paas".equals(containerProperties.getFileUploadType())) {
                url = paasService.upload(multipartFile, parameterMap);
                m.put("type", "paas");
            } else {
                ///其它也采用本地上传-配置名称错误时
                url = localService.upload(multipartFile, parameterMap);
                m.put("type", "local");
            }
            if (url.startsWith("ERROR:")) {
                return RestResponse.failure(url);
            }
            m.put("size", String.valueOf(multipartFile.getSize()));
            m.put("url", url);
            m.put("name", multipartFile.getName());
            LOGGER.info(httpServletRequest.getRemoteHost() + "上传文件->name:" + multipartFile.getName() + " url:" + url);
        } catch (Exception e) {
            LOGGER.info(httpServletRequest.getRemoteHost() + "上传文件出错->" + e.getMessage());
            return RestResponse.failure(e.getMessage());
        }
        return RestResponse.success().setData(m);
    }

    /**
     * wangEditor批量上传图片
     */
    @PostMapping("uploadWang")
    @ApiOperation(value = "图片批量上传接口[未启用]", httpMethod = HttpMethod.POST)
    @SysLog("图片批量上传接口")
    public Map<String, Object> uploadWang(@RequestParam("file") MultipartFile[] file, HttpServletRequest httpServletRequest) {
        if (file == null || file.length == 0) {
            return RestResponse.failure("上传文件为空 ");
        }
        Map<String, Object> parameterMap = MapUtil.newHashMap();
        parameterMap.put("AREA_ID", httpServletRequest.getParameter("s_areaId"));
        List<String> data = Lists.newArrayList();
        Map<String, Object> m = Maps.newHashMap();
        try {
            for (MultipartFile aFile : file) {
                String url = null;
                if ("local".equals(containerProperties.getFileUploadType())) {
                    url = localService.upload(aFile, parameterMap);
                }

                if ("myOss".equals(containerProperties.getFileUploadType())) {
                    url = myossService.upload(aFile, parameterMap);
                }
                if ("paas".equals(containerProperties.getFileUploadType())) {
                    url = paasService.upload(aFile, parameterMap);
                    m.put("type", "paas");
                }
                data.add(url);
            }
            m.put("errno", 0);
        } catch (Exception e) {
            e.printStackTrace();
            m.put("errno", 1);
        }
        m.put("data", data);
        return m;
    }


    @PostMapping("downCheck")
    @ApiOperation(value = "检查是否能下载[未启用]", httpMethod = HttpMethod.POST)
    @ResponseBody
    @SysLog("文件下载检查接口")
    public RestResponse downCheck(@RequestParam(value = "url", required = false) String url, @RequestParam(value = "name", required = false) String name) {
        if (StringUtils.isBlank(url)) {
            return RestResponse.failure("图片地址不能为空");
        }
        if (StringUtils.isBlank(name)) {
            return RestResponse.failure("图片名称不能为空");
        }
        return RestResponse.success();
    }

    @GetMapping("download")
    @ApiOperation(value = "文件下载[未启用]", httpMethod = HttpMethod.GET)
    @ApiImplicitParams({@ApiImplicitParam(name = "url", value = "文件真实路径", paramType = "query"), @ApiImplicitParam(name = "name", value = "文件名称", paramType = "query")})
    @SysLog("文件下载服务")
    public RestResponse downFile(@RequestParam(value = "url", required = false) String realurl, @RequestParam(value = "name", required = false) String name, HttpServletResponse response) throws IOException {
        if (StringUtils.isBlank(realurl)) {
            return RestResponse.failure("图片地址不能为空");
        }
        if (StringUtils.isBlank(name)) {
            return RestResponse.failure("图片名称不能为空");
        }
        if ("text/html".equals(ToolUtil.getContentType(name))) {
            return RestResponse.failure("图片格式不正确");
        }
        name = new String(name.getBytes("GB2312"), "ISO8859-1");
        URL url = new URL(realurl);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.connect();
        BufferedInputStream br = new BufferedInputStream(conn.getInputStream());
        byte[] buf = new byte[1024];
        int len;
        response.reset();
        response.setHeader("Content-type", "application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=" + name);
        ServletOutputStream out = response.getOutputStream();
        while ((len = br.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        br.close();
        out.flush();
        out.close();
        conn.disconnect();
        return RestResponse.success();
    }


    public String localUpload(HttpServletRequest request, MultipartFile file) {
        if (!file.isEmpty()) {
            try {
                // 文件保存路径
                if (StringUtils.isBlank(localUploadPath)) {
                    localUploadPath = request.getSession().getServletContext().getRealPath("/") + "/static/upload/" + System.currentTimeMillis() + "/";
                    String filePath = localUploadPath + file.getOriginalFilename();
                    file.transferTo(new File(filePath));
                    return filePath;
                } else {
                    Long t = System.currentTimeMillis();
                    String filePath = localUploadPath + t + "/" + file.getOriginalFilename();
                    file.transferTo(new File(filePath));
                    return "/upload/" + t + filePath;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        } else {
            return null;
        }
    }
}
